package com.ninong.ker.admin.service.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ninong.ker.admin.domain.FwTenant;
import com.ninong.ker.admin.domain.FwTenantUser;
import com.ninong.ker.admin.mapper.FwTenantMapper;
import com.ninong.ker.admin.mapper.FwTenantUserMapper;
import com.ninong.ker.admin.service.LoginService;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.ninong.ker.admin.domain.User;
import com.ninong.ker.admin.mapper.DicMapper;
import com.ninong.ker.admin.mapper.LoginMapper;
import com.ninong.ker.admin.rest.vo.MenuVO;
import com.ninong.ker.admin.service.dto.UserDTO;
import com.ninong.ker.common.auth.JwtProperties;
import com.ninong.ker.common.auth.SecurityAdmin;
import com.ninong.ker.common.exception.CmdException;
import com.ninong.ker.common.response.CmdResponse;
import com.ninong.ker.common.tools.CmdAdminTools;
import com.ninong.ker.common.tools.RedisUtils;
import com.ninong.ker.common.tools.enums.BusinessEnum;
import com.ninong.ker.common.user.OnlineUser;

import cn.hutool.crypto.SecureUtil;
import org.springframework.transaction.annotation.Transactional;

/**
 * @author 鸠摩智
 * @date 2020年12月3日 上午11:10:05
 */
@Service
@Transactional(rollbackFor = RuntimeException.class)
public class LoginServiceImpl extends ServiceImpl<LoginMapper, User> implements LoginService {

    private static final String BUTTON = "button";
    private static final String MENU = "menu";
    private static final String PARENT = "0";
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private SecurityAdmin securityAdmin;
    @Autowired
    private JwtProperties properties;
    @Autowired
    private DicMapper dicMapper;
    @Autowired
    private FwTenantUserMapper tenantUserMapper;
    @Autowired
    private FwTenantMapper tenantMapper;

    @Override
    public CmdResponse login(UserDTO user) throws Exception {
//        if (!redisUtils.haskey(user.getUuid())) {
//            throw new CmdException(BusinessEnum.VERIFICATION_CODE_EXPIRED);
//        }
//        // 查询验证码
//        String code = redisUtils.get(user.getUuid()).toString();
//        // 清除验证码
//        redisUtils.del(user.getUuid());
//        if (StringUtils.isBlank(code)) {
//            throw new CmdException(BusinessEnum.VERIFICATION_CODE_ERROR);
//        }
//        if (StringUtils.isBlank(user.getCode()) || !user.getCode().equalsIgnoreCase(code)) {
//            throw new CmdException(BusinessEnum.VERIFICATION_CODE_ERROR);
//        }
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getPhone, user.getPhone());
        queryWrapper.eq(User::getDeleted, true);
        User login = baseMapper.selectOne(queryWrapper);
        if (ObjectUtils.isEmpty(login)) {
            throw new CmdException(BusinessEnum.USER_NAME_AND_PASSWORD);
        } else {
            if (!login.getEnabled()) {
                throw new CmdException(BusinessEnum.USER_ENABLED);
            }
        }
        user.setPassword(CmdAdminTools.decryptByPrivateKey(properties.privateKey, user.getPassword()));
        String password = SecureUtil.md5(login.getSalt() + user.getPassword());
        if (!StringUtils.equals(login.getPassword(), password)) {
            throw new CmdException(BusinessEnum.USER_NAME_AND_PASSWORD);
        }
        Map<String, Object> param = Maps.newHashMap();
        param.put("id", login.getId());
        param.put("type", BUTTON);
        List<String> roles = baseMapper.findAuthorities(param);
        // 生成令牌
        String token = securityAdmin.createToken(login.getId());
        Map<String, Object> responseMap = Maps.newHashMap();
        login.setPassword(null);
        responseMap.put("user", login);
        responseMap.put("dics", dicMapper.getDicTree());
        // 根据登录用户id 获得所在的租户集合
        List<FwTenantUser> tenants = tenantUserMapper.selectList(new LambdaQueryWrapper<FwTenantUser>().eq(FwTenantUser::getUserId, login.getId()));
        String tenantId = "";
        if (ObjectUtils.isNotEmpty(tenants)) {
            tenantId = tenants.get(0).getTenantId();
        }
        OnlineUser online = new OnlineUser(roles, login.getId(), login.getDeptId(), login.getDeptName(),login.getNickName(), login.getPhone(), login.getEmail(), new Date(), tenantId);
        redisUtils.set(properties.getOnline() + token, JSONObject.toJSON(online), properties.getValidity() / 1000);
        responseMap.put("token", token);
        if (ObjectUtils.isNotEmpty(tenants)) {
            List<String> ids = Lists.newArrayList();
            tenants.forEach(item -> {
                ids.add(item.getTenantId());
            });
            List<FwTenant> tens = tenantMapper.selectList(new LambdaQueryWrapper<FwTenant>().in(FwTenant::getId, ids));
            responseMap.put("tenants", tens);
            responseMap.put("tenantName", tens.get(0).getTenantName());
        } else {
            responseMap.put("tenants", Lists.newArrayList());
            responseMap.put("tenantName", "");
        }
        CmdResponse response = new CmdResponse();
        response.setData(responseMap);
        return response;
    }

    @Override
    public List<MenuVO> listMenus() {
        OnlineUser onlineUser = securityAdmin.currentUser();
        Map<String, Object> param = Maps.newHashMap();
        param.put("uid", onlineUser.getId());
        param.put("pid", PARENT);
        param.put("type", MENU);
        if (StringUtils.isEmpty(onlineUser.getTenantId())) {
            List<MenuVO> vos = baseMapper.getMenus(param);
            return vos;
        } else {
            param.put("tenantId", onlineUser.getTenantId());
            List<MenuVO> vos = baseMapper.getTenantMenus(param);
            return vos;
        }
    }

    @Override
    public List<String> listInfo() {
        OnlineUser user = securityAdmin.currentUser();
        Map<String, Object> param = Maps.newHashMap();
        param.put("id", user.getId());
        param.put("type", BUTTON);
        List<String> roles = baseMapper.findAuthorities(param);
        return roles;
    }

    @Override
    public PageInfo<JSONObject> listOnline(UserDTO dto) {
        List<String> onlines = redisUtils.findkeysForPage(properties.getOnline() + "*", dto.getCurrentPage(),
                dto.getPageSize());
        ArrayList<JSONObject> list = Lists.newArrayList();
        onlines.forEach(cmd -> {
            JSONObject json = JSONObject.parseObject(redisUtils.get(cmd).toString());
            json.put("id", cmd);
            list.add(json);
        });
        long total = redisUtils.lGetListSize(properties.getOnline() + "*");
        PageInfo<JSONObject> info = new PageInfo<JSONObject>();
        info.setList(list);
        info.setTotal(total);
        return info;
    }

    @Override
    public void removeOnline(String[] keys) {
        List<String> list = Arrays.asList(keys);
        list.forEach(key -> {
            redisUtils.del(key);
        });
    }

    @Override
    public  Map<String, Object> changeTenant(String id) {
        OnlineUser onlineUser = new OnlineUser();
        String token = securityAdmin.getToken();
        Object tokens = redisUtils.get(properties.getOnline() + token);
        if (!org.springframework.util.ObjectUtils.isEmpty(tokens)) {
            String login = tokens.toString();
            onlineUser = JSONObject.parseObject(login, OnlineUser.class);
        }
        onlineUser.setTenantId(id);
        redisUtils.set(properties.getOnline() + token, JSONObject.toJSON(onlineUser), properties.getValidity() / 1000);
        FwTenant tenant = tenantMapper.selectById(id);
        Map<String, Object> responseMap = Maps.newHashMap();
        responseMap.put("dics", dicMapper.getDicTree());
        responseMap.put("tenant", tenant);
        return responseMap;
    }
}
